using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using JVIT.TimeSheet.BLL;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Collections.Generic;
using System.Threading;
using System.Configuration;

//TODO:
//
// + lock after pause
// + resume after unlock
// + tooltip with current task + starttime today
// + when starting new task on new day, select current date => when unlock is on a new day, switch to new day and run Start()
// + close button in contextmenu of tray icon
// + pausing winamp when going into pause state

namespace JVIT.TimeSheet.GUI
{
    public partial class frmTimesheet : Form
    {
        private string extension = ".xml";
        private FormWindowState m_previousWindowState;
        private string _storageDir = "";
        private string StorageDir
        {
            get
            {
                if (_storageDir == "")
                {
                    _storageDir = ConfigurationManager.AppSettings["StorageLocation"];
                }
#if DEBUG
#else
                if (_storageDir == "")
                {
                    _storageDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                    _storageDir = Path.Combine(_storageDir, "JVIT.TimeSheet");
                    if (!Directory.Exists(_storageDir))
                        Directory.CreateDirectory(_storageDir);
                }
#endif
                return _storageDir;
            }
        }
        private WorkItems _workItems;
        public WorkItems WorkItems
        {
            get
            {
                if (_workItems == null) _workItems = new WorkItems();
                return _workItems;
            }
            set
            {
                _workItems = value;
            }
        }

        public frmTimesheet()
        {
            InitializeComponent();
            dgvDayView.AutoGenerateColumns = false;

            dateTimePicker1.Value = DateTime.Now.Date;
            //ApplyChanges();
            // Store the initial window state that we want to restore to when we double-click the tray icon
            m_previousWindowState = (this.WindowState == FormWindowState.Minimized ? FormWindowState.Normal : this.WindowState);
            SystemEvents.SessionSwitch += new SessionSwitchEventHandler(SystemEvents_SessionSwitch);
        }

        void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
        {
            if (e.Reason == SessionSwitchReason.SessionUnlock)
                if (this.WorkItems.WorkState == WorkState.Paused)
                    Resume();
            if (this.WorkItems.WorkState == WorkState.Stopped && DateTime.Now.Date > dateTimePicker1.Value.Date)
            {
                dateTimePicker1.Value = DateTime.Now;
                if (this.WorkItems.WorkState == WorkState.Stopped)
                {
                    Start();
                    WinampControl.Play();
                }
            }
        }
        public void ApplyChanges()
        {
            DisplayWorkItems();
            WriteFile();
            ResetButtons();
        }
        private void ResetNotifyIconToolTip(string workedToday)
        {
            string text = string.Format("{1}: {2}{0}{4}",
                                                 Environment.NewLine,
                                                 this.WorkItems.FirstOrDefault() == null ? "" : this.WorkItems.FirstOrDefault().Started.Value.ToLongTimeString(),
                                                 workedToday,
                                                 this.WorkItems.WorkState,
                                                 this.WorkItems.ActiveWorkItem == null ? "" : this.WorkItems.ActiveWorkItem.Description
                                                 );
            notifyIcon1.Text = text.Length > 63 ? text.Substring(0, 63) : text;
        }
        public void DisplayWorkItems()
        {
            richTextBox1.Text = "";
            List<WorkItemView> workItems = (from WorkItem workItem in this.WorkItems
                                            select new WorkItemView()
                                            {
                                                Order = 0,
                                                Description = workItem.Description,
                                                From = workItem.Started.ToReadableString(),
                                                To = workItem.Ended.ToReadableString(),
                                                Duration = workItem.TotalDurationUnfinished.ToReadableString(),
                                                PauseCount = workItem.Pauses.Count,
                                                PauseDuration = workItem.Pauses.TotalDurationUnfinished.ToReadableString(),
                                                Pauses = workItem.Pauses,
                                                WorkItem = workItem
                                            }).ToList();

            lvWorkItems.Items.Clear();
            foreach (WorkItemView workItem in workItems)
            {
                ListViewItem item = new ListViewItem(workItem.Description);
                item.SubItems.Add(new System.Windows.Forms.ListViewItem.ListViewSubItem(item, workItem.From));
                item.SubItems.Add(new System.Windows.Forms.ListViewItem.ListViewSubItem(item, workItem.To));
                item.SubItems.Add(new System.Windows.Forms.ListViewItem.ListViewSubItem(item, workItem.Duration));
                item.SubItems.Add(new System.Windows.Forms.ListViewItem.ListViewSubItem(item, workItem.PauseCount.ToString()));
                item.SubItems.Add(new System.Windows.Forms.ListViewItem.ListViewSubItem(item, workItem.PauseDuration));
                item.BackColor = string.IsNullOrEmpty(workItem.To) ? Color.LightBlue : Color.LightCyan;
                lvWorkItems.Items.Add(item);

                #region textbox
                richTextBox1.Text += "Task: " + workItem.Description + Environment.NewLine;
                richTextBox1.Text += "Duration: " + workItem.Duration + Environment.NewLine;
                richTextBox1.Text += string.Format("From {0} to {1}", workItem.From, workItem.To) + Environment.NewLine;
                richTextBox1.Text += "    Pause" + (workItem.PauseCount > 1 ? "s" : "") + " (" + workItem.PauseDuration + "):" + Environment.NewLine;
                foreach (Pause pause in workItem.Pauses)
                {
                    richTextBox1.Text += string.Format("    From {0} to {1}", pause.Started.ToReadableString(), pause.Ended.ToReadableString()) + Environment.NewLine;
                }

                if (string.IsNullOrEmpty(workItem.To) == false && workItem != workItems.Last())
                    richTextBox1.Text += "-------------------------" + Environment.NewLine;
                #endregion
            }

            WorkItemView dayTotal = new WorkItemView()
            {
                Description = "Day totals",
                From = this.WorkItems.Started.ToReadableString(),
                To = this.WorkItems.Ended.ToReadableString(),
                Duration = this.WorkItems.TotalDurationUnfinished.ToReadableString(),
                PauseCount = this.WorkItems.Sum(w => w.Pauses.Count),
                PauseDuration = this.WorkItems.PausesDurationUnfinished.ToReadableString()
            };

            ResetNotifyIconToolTip(dayTotal.Duration);

            ListViewItem dayTotalItem = new ListViewItem(dayTotal.Description);
            dayTotalItem.SubItems.Add(new System.Windows.Forms.ListViewItem.ListViewSubItem(dayTotalItem, dayTotal.From));
            dayTotalItem.SubItems.Add(new System.Windows.Forms.ListViewItem.ListViewSubItem(dayTotalItem, dayTotal.To));
            dayTotalItem.SubItems.Add(new System.Windows.Forms.ListViewItem.ListViewSubItem(dayTotalItem, dayTotal.Duration));
            dayTotalItem.SubItems.Add(new System.Windows.Forms.ListViewItem.ListViewSubItem(dayTotalItem, dayTotal.PauseCount.ToString()));
            dayTotalItem.SubItems.Add(new System.Windows.Forms.ListViewItem.ListViewSubItem(dayTotalItem, dayTotal.PauseDuration));
            dayTotalItem.BackColor = Color.Transparent;
            lvWorkItems.Items.Add(dayTotalItem);

            #region textbox
            richTextBox1.Text += Environment.NewLine + "=========================" + Environment.NewLine;
            richTextBox1.Text += string.Format("Started: {0}", this.WorkItems.Started.ToReadableString()) + Environment.NewLine;
            richTextBox1.Text += string.Format("Stopped: {0}", this.WorkItems.Ended.ToReadableString()) + Environment.NewLine;
            richTextBox1.Text += string.Format("Pauses ({0}): {1}", this.WorkItems.Sum(w => w.Pauses.Count), this.WorkItems.PausesDurationUnfinished.ToReadableString()) + Environment.NewLine;
            richTextBox1.Text += string.Format("Worked: {0}", this.WorkItems.TotalDurationUnfinished.ToReadableString()) + Environment.NewLine;
            #endregion

            lvWorkItems.Refresh();

            workItems.Add(dayTotal);
            dgvDayView.DataSource = workItems;
            //dgvDayView.Refresh();

            richTextBox1_TextChanged(null, null);
        }
        public void WriteFile()
        {
            WriteObject();
        }
        public void ResetButtons()
        {
            btnStart.Enabled = btnStop.Enabled = btnPause.Enabled = btnStopStart.Enabled = false;
            startToolStripMenuItem.Enabled = stopToolStripMenuItem.Enabled = pauseToolStripMenuItem.Enabled = stopStartToolStripMenuItem.Enabled = false;
            switch (this.WorkItems.WorkState)
            {
                case WorkState.Stopped:
                    startToolStripMenuItem.Enabled = btnStart.Enabled = true;
                    btnStop.Enabled = timer2.Enabled;
                    break;
                case WorkState.Started:
                    stopToolStripMenuItem.Enabled = pauseToolStripMenuItem.Enabled = btnStop.Enabled = btnPause.Enabled = stopStartToolStripMenuItem.Enabled = btnStopStart.Enabled = true;
                    pauseToolStripMenuItem.Text = btnPause.Text = "Pause";
                    break;
                case WorkState.Paused:
                    pauseToolStripMenuItem.Enabled = btnPause.Enabled = true;
                    pauseToolStripMenuItem.Text = btnPause.Text = "Resume";
                    break;
            }
        }
        private void btnStart_Click(object sender, EventArgs e)
        {
            Start();
        }
        private void Start()
        {
            string description = Prompt.ShowDialog("Beschrijf de taak waar u aan gaat werken:", "Nieuwe taak");
            if (string.IsNullOrEmpty(description) == false)
                this.WorkItems.Start(description);
            ApplyChanges();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            if (timer2.Enabled)
            {
                timer2.Stop();
                btnStop.Text = "Stop";
                ResetButtons();
            }
            else
            {
                Stop();
                timer2.Tag = 3;
                UpdateStopButton();
                timer2.Start();
                ResetButtons();
            }
        }
        private void Stop()
        {
            this.WorkItems.Stop();
            ApplyChanges();
            Thread.Sleep(1000);
            WinampControl.Stop();
        }
        //        private void FullStop()
        //        {
        //            Stop();
        //#if DEBUG
        //#else
        //            LockWorkStation();
        //#endif
        //        }

        private void btnPause_Click(object sender, EventArgs e)
        {
            PauseResume();
        }
        private void PauseResume()
        {
            if (this.WorkItems.WorkState == WorkState.Paused)
            {
                if (timer1.Enabled)
                {
                    timer1.Stop();
                    btnPause.Text = "Resume";
                }
                else
                {
                    Resume();
                }
            }
            else
            {
                Pause();
            }
        }
        private void Pause()
        {
            if (this.WorkItems.WorkState == WorkState.Started)
            {
                this.WorkItems.Pause();
                ApplyChanges();
                timer1.Tag = 3;
                UpdatePauseButton();
                timer1.Start();
                WinampControl.Pause();
            }
        }
        private void Resume()
        {
            if (this.WorkItems.WorkState == WorkState.Paused)
            {
                timer1.Stop();
                this.WorkItems.Resume();
                ApplyChanges();
                Thread.Sleep(1000);
                WinampControl.Pause();
            }
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            // We need to keep track of whether you’re minimizing from a normal or maximized window
            if (this.WindowState != FormWindowState.Minimized)
            {
                m_previousWindowState = this.WindowState;
            }
            notifyIcon1.Visible = (this.WindowState == FormWindowState.Minimized);
            notifyIcon1.ShowBalloonTip(1000);
            this.Visible = !notifyIcon1.Visible;
        }
        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            RestoreWindowState();
        }
        private void RestoreWindowState()
        {
            this.Visible = true;
            notifyIcon1.Visible = false;
            this.WindowState = m_previousWindowState;
        }

        public void PrintDocument()
        {
            //Create an instance of our printer class
            PCPrint printer = new PCPrint();
            //Set the font we want to use
            printer.PrinterFont = new Font("Courier New", 10);
            //Set the TextToPrint property
            printer.TextToPrint = richTextBox1.Text;
            printer.PrinterSettings.PrinterName = "PDFCreator";
            //Issue print command
            printer.Print();
        }

        private void btnPrint_Click(object sender, EventArgs e)
        {
            PrintDocument();
        }

        private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
        {
            ChangeDate(dateTimePicker1.Value);
        }

        private void ChangeDate(DateTime dateTime)
        {
            ReadObject();
            DisplayWorkItems();
            ResetButtons();
        }

        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            btnPrint.Enabled = richTextBox1.Text.Length > 0 || lvWorkItems.Items.Count > 1;
        }
        public string GetFileName()
        {
            return Path.Combine(this.StorageDir, dateTimePicker1.Value.Date.ToString("yyyy-MM-dd") + this.extension);
        }
        public void WriteObject()
        {
            FileStream writer = new FileStream(GetFileName(), FileMode.Create);
            DataContractSerializer ser = new DataContractSerializer(typeof(WorkItems));
            ser.WriteObject(writer, this.WorkItems);
            writer.Close();
        }

        public void ReadObject()
        {
            if (File.Exists(GetFileName()))
            {
                FileStream fs = new FileStream(GetFileName(), FileMode.Open);
                XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
                DataContractSerializer ser = new DataContractSerializer(typeof(WorkItems));
                // Deserialize the data and read it from the instance.
                this.WorkItems = (WorkItems)ser.ReadObject(reader, true);
                reader.Close();
                fs.Close();
            }
            else
            {
                this.WorkItems = null;
            }
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void printToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PrintDocument();
        }

        private void stopStartToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Stop();
            Start();
        }

        private void btnStopStart_Click(object sender, EventArgs e)
        {
            Stop();
            Start();
        }
        private void LockWindows()
        {
            //System.Diagnostics.Process.Start("shutdown", "/l");
#if DEBUG
            MessageBox.Show("Lock workstation");
#else
            LockWorkStation();
#endif
            ResetButtons();
        }

        [DllImport("user32.dll")]
        public static extern void LockWorkStation();

        private void timer1_Tick(object sender, EventArgs e)
        {
            if ((int)timer1.Tag == 0)
            {
                LockWindows();
            }
            else
            {
                UpdatePauseButton();
                timer1.Tag = (int)timer1.Tag - 1;
            }
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            if ((int)timer2.Tag == 0)
            {
                timer2.Stop();
                LockWindows();
                btnStop.Text = "Stop";
            }
            else
            {
                UpdateStopButton();
                timer2.Tag = (int)timer2.Tag - 1;
            }
        }

        private void UpdatePauseButton()
        {
            btnPause.Text = string.Format("Lock in {0} sec.", timer1.Tag);
        }

        private void UpdateStopButton()
        {
            btnStop.Text = string.Format("Lock in {0} sec.", timer2.Tag);
        }

        private void tmrRefresh_Tick(object sender, EventArgs e)
        {
            DisplayWorkItems();
        }

        private void lvWorkItems_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (lvWorkItems.SelectedIndices[0] < this.WorkItems.Count)
            {
                MessageBox.Show(this.WorkItems[lvWorkItems.SelectedIndices[0]].Description);
                WorkItemDetail workItemDetail = new WorkItemDetail(this.WorkItems[lvWorkItems.SelectedIndices[0]]);
                if (workItemDetail.ShowDialog() == DialogResult.OK)
                    MessageBox.Show(workItemDetail.ToString());
            }
        }

        private void lvWorkItems_SelectedIndexChanged(object sender, EventArgs e)
        {
        }

        private void dgvDayView_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            if (dgvDayView.DataSource != null)
            {
                //for (int rowNr = 0; rowNr < dgvDayView.Rows.Count; rowNr++ )
                foreach (DataGridViewRow row in dgvDayView.Rows)
                {
                    WorkItemView currentItem = (WorkItemView)row.DataBoundItem;

                    row.DefaultCellStyle.Font = new Font("Microsoft Sans Serif", 8, FontStyle.Regular);
                    if (this.WorkItems.Contains(currentItem.WorkItem) == false)
                    {
                        row.DefaultCellStyle.BackColor = SystemColors.Window;
                        row.DefaultCellStyle.Font = new Font(row.DefaultCellStyle.Font, FontStyle.Bold);
                    }
                    else if (string.IsNullOrEmpty(currentItem.To)) row.DefaultCellStyle.BackColor = Color.LightBlue;
                    else row.DefaultCellStyle.BackColor = Color.LightCyan;

                    row.Cells[0].Value = currentItem.Description;
                    row.Cells[1].Value = currentItem.From;
                    row.Cells[2].Value = currentItem.To;
                    row.Cells[3].Value = currentItem.Duration;
                    row.Cells[4].Value = currentItem.PauseCount;
                    row.Cells[5].Value = currentItem.PauseDuration;
                }
            }
        }

        private void dgvDayView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (dgvDayView.SelectedRows[0].Index < this.WorkItems.Count)
            {
                DataGridViewRow row = dgvDayView.SelectedRows[0];
                WorkItemView currentItem = (WorkItemView)row.DataBoundItem;
                WorkItem currentWorkItem = currentItem.WorkItem;//this.WorkItems[dgvDayView.SelectedRows[0].Index];
                WorkItemDetail workItemDetail = new WorkItemDetail(currentWorkItem);
                if (workItemDetail.ShowDialog() == DialogResult.OK)
                {
                    ApplyChanges();
                }
            }
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RestoreWindowState();
        }

        private void btnMinimize_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private void lockToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LockWindows();
        }
    }
}
